/******************************************************************************
 * Copyright 2007 - 2021 Realtek Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/
 
#define _HARMONY_SDIO_OPS_C_

#include <drv_types.h>
#include "rtw_debug.h"
#include "sdio_if.h"
#include "drv_types_sdio.h"
#include "harmony_sdio_ops.h"

/* The unit of return value is Hz */
static inline u32 rtw_sdio_get_clock(struct dvobj_priv *d)
{
	return d->intf_data.clock;
}



static inline bool rtw_is_sdio30(_adapter *adapter)
{
	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
	PSDIO_DATA psdio_data = &dvobj->intf_data;

	return (psdio_data->sd3_bus_mode) ? _TRUE : _FALSE;
}

static bool rtw_sdio_claim_host_needed(DevHandle* sdio_handle)
{
	//struct dvobj_priv *dvobj = sdio_get_drvdata(func);
	//PSDIO_DATA sdio_data = &dvobj->intf_data;

	//if (sdio_data->sys_sdio_irq_thd && sdio_data->sys_sdio_irq_thd == current)
	//	return _FALSE;
	return _TRUE;
	//return _FALSE;
}

inline void rtw_sdio_set_irq_thd(struct dvobj_priv *dvobj, _thread_hdl_ thd_hdl)
{
	PSDIO_DATA sdio_data = &dvobj->intf_data;

	sdio_data->sys_sdio_irq_thd = thd_hdl;
}
#ifndef RTW_HALMAC
u8 sd_f0_read8(struct intf_hdl *pintfhdl,u32 addr, s32 *err)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;
	
	u8 v=0;

	DevHandle sdio_handle;
	bool claim_needed;

	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;

	//device not remove
	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return v;
	}	
	
	//get claim_needed host func
	sdio_handle = psdio->handle;
	claim_needed = rtw_sdio_claim_host_needed(sdio_handle);

	if (claim_needed)
		SdioClaimHost(sdio_handle);
	err = SdioReadBytesFromFunc0(sdio_handle,v,addr,1,0);
	if (claim_needed)
		SdioReleaseHost(sdio_handle);
	if (err)
		RTW_DBG(KERN_ERR "%s: FAIL!(%d) addr=0x%05x\n", __func__, err, addr);

	return v;
}

void sd_f0_write8(struct intf_hdl *pintfhdl, u32 addr, u8 v, s32 *err)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;	
	bool claim_needed;
	DevHandle sdio_handle;
	
	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;

	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return;
	}	
	
	//func = psdio->func;
	sdio_handle = psdio->handle;
	claim_needed = rtw_sdio_claim_host_needed(sdio_handle);

	if (claim_needed)
		SdioClaimHost(sdio_handle);
	err = SdioWriteBytesToFunc0(sdio_handle,v,addr,1,0);
	if (claim_needed)
		SdioReleaseHost(sdio_handle);
	if (err)
		RTW_DBG(KERN_ERR "%s: FAIL!(%d) addr=0x%05x val=0x%02x\n", __func__, err, addr, v);

}

/*
 * Return:
 *	0		Success
 *	others	Fail
 */
s32 _sd_cmd52_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;

	int err=0, i;
	DevHandle sdio_handle;
	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;

	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return err;
	}

	sdio_handle = psdio->handle;
	for (i = 0; i < cnt; i++) {
		err = SdioReadBytes(sdio_handle, ((u8 *)pdata)[i], addr+i, 1, 0);
		if (err) {
			RTW_DBG(KERN_ERR "%s: FAIL!(%d) addr=0x%05x\n", __func__, err, addr+i);
			break;
		}
	}

	return err;
}

/*
 * Return:
 *	0		Success
 *	others	Fail
 */
s32 sd_cmd52_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;
	
	int err=0, i;
	//struct sdio_func *func;
	DevHandle sdio_handle;
	bool claim_needed;	

	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;

	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return err;
	}	

	//func = psdio->func;
	sdio_handle = psdio->handle;
	claim_needed = rtw_sdio_claim_host_needed(sdio_handle);

	if (claim_needed)
		SdioClaimHost(sdio_handle);
	err = _sd_cmd52_read(pintfhdl, addr, cnt, pdata);
	if (claim_needed)
		SdioReleaseHost(sdio_handle);

	return err;
}

/*
 * Return:
 *	0		Success
 *	others	Fail
 */
s32 _sd_cmd52_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;
	
	int err=0, i;
	//struct *sdio_func *func;
	DevHandle sdio_handle;
	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;

	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return err;
	}

	
	//spin_lock(&padapter->xmit_recv_mutex);
	//func = psdio->func;
	sdio_handle = psdio->handle;
	for (i = 0; i < cnt; i++) {
		err = SdioWriteBytes(handle, ((u8 *)pdata)[i], addr+i, 1,0);
		if (err) {
			RTW_DBG(KERN_ERR "%s: FAIL!(%d) addr=0x%05x val=0x%02x\n", __func__, err, addr+i, pdata[i]);
			break;
		}
	}
	//spin_unlock(&padapter->xmit_recv_mutex);

	return err;
}

/*
 * Return:
 *	0		Success
 *	others	Fail
 */
s32 sd_cmd52_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;
	
	int err=0, i;
	//struct sdio_func *func;
	DevHandle sdio_handle;
	bool claim_needed;

	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;

	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return err;
	}

	
	//spin_lock(&padapter->xmit_recv_mutex);
	//func = psdio->func;
	sdio_handle = psdio->handle;
	claim_needed = rtw_sdio_claim_host_needed(sdio_handle);

	if (claim_needed)
		SdioClaimHost(sdio_handle);
	err = _sd_cmd52_write(pintfhdl, addr, cnt, pdata);
	if (claim_needed)
		SdioReleaseHost(sdio_handle);
	//spin_unlock(&padapter->xmit_recv_mutex);

	return err;
}

u8 _sd_read8(struct intf_hdl *pintfhdl, u32 addr, s32 *err)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;

	u8 v=0;
	//struct sdio_func *func;
	DevHandle sdio_handle;
	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;

	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return v;
	}

	
	//spin_lock(&padapter->xmit_recv_mutex);
	//func = psdio->func;
	sdio_handle = psdio->handle;
	err = SdioReadBytes(sdio_handle, v, addr, 1, 0);
	if (err && *err)
		RTW_DBG(KERN_ERR "%s: FAIL!(%d) addr=0x%05x\n", __func__, *err, addr);
	//spin_unlock(&padapter->xmit_recv_mutex);

	return v;
}

u8 sd_read8(struct intf_hdl *pintfhdl, u32 addr, s32 *err)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;
	
	u8 v=0;
	//struct sdio_func *func;
	DevHandle sdio_handle;
	bool claim_needed;

	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;

	if (NULL == err) {
		RTW_DBG(" %s err is NULL !!!\n",__FUNCTION__);
		return v;
	}

	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return v;
	}

	
	//spin_lock(&padapter->xmit_recv_mutex);
	//func = psdio->func;
	sdio_handle = psdio->handle;
	claim_needed = rtw_sdio_claim_host_needed(sdio_handle);

	if (claim_needed)
		SdioClaimHost(sdio_handle);
	err = SdioReadBytes(sdio_handle, v, addr, 1, 0);
	if (claim_needed)
		SdioReleaseHost(sdio_handle);
	if (err && *err)
		RTW_DBG(KERN_ERR "%s: FAIL!(%d) addr=0x%05x\n", __func__, *err, addr);
	//spin_unlock(&padapter->xmit_recv_mutex);

	return v;
}

u16 sd_read16(struct intf_hdl *pintfhdl, u32 addr, s32 *err)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;
	
	u16 v=0;
	//struct sdio_func *func;
	DevHandle sdio_handle;
	bool claim_needed;

	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;

	if (NULL == err) {
		RTW_DBG(" %s err is NULL !!!\n",__FUNCTION__);
		return v;
	}

	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return v;
	}

	//spin_lock(&padapter->xmit_recv_mutex);	
	//func = psdio->func;
	sdio_handle = psdio->handle;
	claim_needed = rtw_sdio_claim_host_needed(sdio_handle);

	if (claim_needed)
		SdioClaimHost(sdio_handle);
	err = SdioReadBytes(sdio_handle, &v, addr, 2, 0);
	if (claim_needed)
		SdioReleaseHost(sdio_handle);
	if (err && *err)
		RTW_DBG(KERN_ERR "%s: FAIL!(%d) addr=0x%05x\n", __func__, *err, addr);
	//spin_unlock(&padapter->xmit_recv_mutex);

	return	v;
}

u32 _sd_read32(struct intf_hdl *pintfhdl, u32 addr, s32 *err)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;
	
	u32 v=0;
	//struct sdio_func *func;
	DevHandle sdio_handle;
	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;

	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return v;
	}

		
	//spin_lock(&padapter->xmit_recv_mutex);
	//func = psdio->func;
	sdio_handle = psdio->handle;
	err = SdioReadBytes(sdio_handle, &v, addr, 4, 0);
	if (err)
	{
		RTW_DBG(KERN_ERR "%s: (%d) addr=0x%05x, val=0x%x\n", __func__, err, addr, v);
	}
	//spin_unlock(&padapter->xmit_recv_mutex);

	return	v;
}

u32 sd_read32(struct intf_hdl *pintfhdl, u32 addr, s32 *err)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;
	
	u32 v=0;
	//struct sdio_func *func;
	DevHandle sdio_handle;
	bool claim_needed;

	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;

	if (NULL == err) {
		RTW_DBG(" %s err is NULL !!!\n",__FUNCTION__);
		return v;
	}

	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return v;
	}
	
	//func = psdio->func;
	sdio_handle = psdio->handle;
	claim_needed = rtw_sdio_claim_host_needed(sdio_handle);

	if (claim_needed)
		SdioClaimHost(sdio_handle);
	err = SdioReadBytes(sdio_handle, &v, addr, 4, 0);
	if (claim_needed)
		SdioReleaseHost(sdio_handle);

	if (err)
	{

		RTW_DBG(KERN_ERR "%s: (%d) addr=0x%05x, val=0x%x\n", __func__, *err, addr, v);
	}

	return	v;
}

void sd_write8(struct intf_hdl *pintfhdl, u32 addr, u8 v, s32 *err)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;
	
	//struct sdio_func *func;
	DevHandle sdio_handle;
	bool claim_needed;

	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;

	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return ;
	}

	//func = psdio->func;
	sdio_handle = psdio->handle;
	claim_needed = rtw_sdio_claim_host_needed(sdio_handle);

	if (claim_needed)
		SdioClaimHost(sdio_handle);
	err = SdioWriteBytes(sdio_handle, v, addr, 1,0);
	if (claim_needed)
		SdioReleaseHost(sdio_handle);
	if (err)
		RTW_DBG(KERN_ERR "%s: FAIL!(%d) addr=0x%05x val=0x%02x\n", __func__, err, addr, v);

}

void sd_write16(struct intf_hdl *pintfhdl, u32 addr, u16 v, s32 *err)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;
	
	//struct sdio_func *func;
	DevHandle sdio_handle;
	bool claim_needed;

	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;

	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return ;
	}

	//func = psdio->func;
	sdio_handle = psdio->handle;
	claim_needed = rtw_sdio_claim_host_needed(sdio_handle);

	if (claim_needed)
		SdioClaimHost(sdio_handle);
	//sdio_writew(func, v, addr, err);
	err = SdioWriteBytes(sdio_handle, v, addr, 2,0);
	if (claim_needed)
		SdioReleaseHost(sdio_handle);
	if (err )
		RTW_DBG(KERN_ERR "%s: FAIL!(%d) addr=0x%05x val=0x%04x\n", __func__, err, addr, v);

}

void _sd_write32(struct intf_hdl *pintfhdl, u32 addr, u32 v, s32 *err)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;
	
	//struct sdio_func *func;
	DevHandle sdio_handle;
	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;

	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return ;
	}
	
	sdio_handle = psdio->handle;
	//func = psdio->func;

	err = SdioWriteBytes(sdio_handle, v, addr, 4,0);
	if (err)
	{
		RTW_DBG(KERN_ERR "%s: (%d) addr=0x%05x val=0x%08x\n", __func__, *err, addr, v);
	}

}

void sd_write32(struct intf_hdl *pintfhdl, u32 addr, u32 v, s32 *err)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;
	//struct sdio_func *func;
	DevHandle sdio_handle;
	bool claim_needed;

	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;

	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return ;
	}
	
	//func = psdio->func;
	sdio_handle = psdio->handle;
	claim_needed = rtw_sdio_claim_host_needed(sdio_handle);

	if (claim_needed)
		SdioClaimHost(sdio_handle);
	//sdio_writel(func, v, addr, err);
	err = SdioWriteBytes(sdio_handle, v, addr, 4,0);
	if (claim_needed)
		SdioReleaseHost(sdio_handle);

	if (err )
	{
		

		RTW_DBG(KERN_ERR "%s: (%d) addr=0x%05x val=0x%08x\n", __func__, err, addr, v);

		
	}

}
#endif /* !RTW_HALMAC */
/*
 * Use CMD53 to read data from SDIO device.
 * This function MUST be called after SdioClaimHost() or
 * in SDIO ISR(host had been claimed).
 *
 * Parameters:
 *	psdio	pointer of SDIO_DATA
 *	addr	address to read
 *	cnt 	amount to read
 *	pdata	pointer to put data, this should be a "DMA:able scratch buffer"!
 *
 * Return:
 *	0		Success
 *	others	Fail
 */
s32 _sd_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;
	
	int err= -EPERM;
	//struct sdio_func *func;
	DevHandle sdio_handle;
	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;
	
	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return err;
	}
		
	//func = psdio->func;
	sdio_handle = psdio->handle;
	if ((cnt==1) || (cnt==2))
	{
		int i;
		u8 *pbuf = (u8*)pdata;

		for (i = 0; i < cnt; i++)
		{
			err = SdioReadBytes(sdio_handle, *(pbuf+i), addr+i, 1, 0);
			if (err) {
				RTW_INFO("%s: FAIL!(%d) addr=0x%05x\n", __func__, err, addr);
				break;
			}
		}
		return err;
	}

	err = SdioReadBytes(sdio_handle, pdata, addr, cnt, 0);
	if (err) {
		RTW_INFO("%s: FAIL(%d)! ADDR=%#x Size=%d\n", __func__, err, addr, cnt);
	}

	return err;
}

/*
 * Use CMD53 to read data from SDIO device.
 *
 * Parameters:
 *	psdio	pointer of SDIO_DATA
 *	addr	address to read
 *	cnt 	amount to read
 *	pdata	pointer to put data, this should be a "DMA:able scratch buffer"!
 *
 * Return:
 *	0		Success
 *	others	Fail
 */
s32 sd_read(struct intf_hdl * pintfhdl, u32 addr, u32 cnt, void *pdata)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;	
	
	//struct sdio_func *func;
	DevHandle sdio_handle;
	bool claim_needed;
	s32 err= -EPERM;
	
	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;
	
	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return err;
	}
	sdio_handle = psdio->handle;
	claim_needed = rtw_sdio_claim_host_needed(sdio_handle);

	if (claim_needed)
		SdioClaimHost(sdio_handle);
	err = _sd_read(pintfhdl, addr, cnt, pdata);
	if (claim_needed)
		SdioReleaseHost(sdio_handle);
	return err;
}

/*
 * Use CMD53 to write data to SDIO device.
 * This function MUST be called after SdioClaimHost() or
 * in SDIO ISR(host had been claimed).
 *
 * Parameters:
 *	psdio	pointer of SDIO_DATA
 *	addr	address to write
 *	cnt 	amount to write
 *	pdata	data pointer, this should be a "DMA:able scratch buffer"!
 *
 * Return:
 *	0		Success
 *	others	Fail
 */
s32 _sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;
	
	DevHandle sdio_handle;
	u32 size;
	s32 err=-EPERM;

	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;
	
	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return err;
	}

	sdio_handle = psdio->handle;

	if ((cnt==1) || (cnt==2))
	{
		int i;
		u8 *pbuf = (u8*)pdata;

		for (i = 0; i < cnt; i++)
		{
			err = SdioWriteBytes(sdio_handle, *(pbuf+i), addr+i, 1,0);
			if (err) {
				RTW_INFO("%s: FAIL!(%d) addr=0x%05x val=0x%02x\n", __func__, err, addr, *(pbuf+i));
				break;
			}
		}
		return err;
	}

	size = cnt;
	err = SdioWriteBytes(sdio_handle, pdata, addr, size, 0);
	if (err) {
		RTW_INFO("%s: FAIL(%d)! ADDR=%#x Size=%d(%d)\n", __func__, err, addr, cnt, size);
	}

	return err;
}

/*
 * Use CMD53 to write data to SDIO device.
 *
 * Parameters:
 *	psdio	pointer of SDIO_DATA
 *	addr	address to write
 *	cnt 	amount to write
 *	pdata	data pointer, this should be a "DMA:able scratch buffer"!
 *
 * Return:
 *	0		Success
 *	others	Fail
 */
s32 sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata)
{
	PADAPTER padapter;
	struct dvobj_priv *psdiodev;
	PSDIO_DATA psdio;

	//struct sdio_func *func;
	DevHandle sdio_handle;
	bool claim_needed;
	s32 err=-EPERM;
	padapter = pintfhdl->padapter;
	psdiodev = pintfhdl->pintf_dev;
	psdio = &psdiodev->intf_data;
	
	if (rtw_is_surprise_removed(padapter)) {
		//RTW_DBG(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",__FUNCTION__);
		return err;
	}
	sdio_handle = psdio->handle;
	claim_needed = rtw_sdio_claim_host_needed(sdio_handle);

	if (claim_needed)
		SdioClaimHost(sdio_handle);
	err = _sd_write(pintfhdl, addr, cnt, pdata);
	if (claim_needed)
		SdioReleaseHost(sdio_handle);	
	return err;
}

/**
 *	Returns driver error code,
 *	0	no error
 *	-1	Level 1 error, critical error and can't be recovered
 *	-2	Level 2 error, normal error, retry to recover is possible
 */
static int harmony_io_err_to_drv_err(int err)
{
	if (!err)
		return 0;

	/* critical error */
	if ((err == -ESHUTDOWN) ||
	    (err == -ENODEV) ||
	    (err == -ENOMEDIUM))
		return -1;

	/* other error */
	return -2;
}

/**
 *	rtw_sdio_raw_read - Read from SDIO device
 *	@d: driver object private data
 *	@addr: address to read
 *	@buf: buffer to store the data
 *	@len: number of bytes to read
 *	@fixed:
 *
 *	Reads from the address space of a SDIO device.
 *	Return value indicates if the transfer succeeded or not.
 */
int  rtw_sdio_raw_read(struct dvobj_priv *d, unsigned int addr,
				   void *buf, size_t len, bool fixed)
{
	int error = -EPERM;
	bool f0, cmd52;
	DevHandle handle;
	bool claim_needed;
	u32 offset, i;
	u8 value;
	PSDIO_DATA psdio;
	psdio = &d->intf_data;
	handle = psdio->handle;
	claim_needed = rtw_sdio_claim_host_needed(handle);
	f0 = RTW_SDIO_ADDR_F0_CHK(addr);
	cmd52 = RTW_SDIO_ADDR_CMD52_CHK(addr);
	/*
	 * Mask addr to remove driver defined bit and
	 * make sure addr is in valid range
	 */
	if (f0)
		addr &= 0xFFF;
	else
		addr &= 0x1FFFF;

	//if (claim_needed)
	SdioClaimHost(handle);
	if (f0) {
		offset = addr;
		for (i = 0; i < len; i++, offset++) {
			error = SdioReadBytesFromFunc0(handle,&value,offset,1,0);			
			if (error)
				break;
			((u8 *)buf)[i] = value;
		}
	} else {
		if (cmd52) {
			offset = addr;
			for (i = 0; i < len; i++) {
				error = SdioReadBytes(handle, &value, offset, 1, 0);
				if (error)
					break;
				offset++;
				((u8 *)buf)[i] = value;
				//RTW_INFO("value:%d,buf[%d]:%d\n",value,i,((u8 *)buf)[i]);
			}
		} else {
			if(fixed==0)
			{
				error = SdioReadBytes(handle,buf,addr,len,0);
			}
			else{
				error = SdioReadBytesFromFixedAddr(handle,buf,addr,len,0);
			}
		}
	}
	//if (claim_needed)
		SdioReleaseHost(handle);
	if(error!=0)
	{
		RTW_INFO("SdioReadBytes error:%d\n",error);
	}

	return harmony_io_err_to_drv_err(error);
}

/**
 *	rtw_sdio_raw_write - Write to SDIO device
 *	@d: driver object private data
 *	@addr: address to write
 *	@buf: buffer that contains the data to write
 *	@len: number of bytes to write
 *	@fixed: address is fixed(FIFO) or incremented
 *
 *	Writes to the address space of a SDIO device.
 *	Return value indicates if the transfer succeeded or not.
 */
int  rtw_sdio_raw_write(struct dvobj_priv *d, unsigned int addr,
				    void *buf, size_t len, bool fixed)
{
	int error = -EPERM;
	bool f0, cmd52;
	DevHandle handle;
	bool claim_needed;
	u32 offset, i;
	u8 value;
	PSDIO_DATA psdio;
	psdio=&d->intf_data;
	handle = psdio->handle;
	
	claim_needed = rtw_sdio_claim_host_needed(handle);
	f0 = RTW_SDIO_ADDR_F0_CHK(addr);
	cmd52 = RTW_SDIO_ADDR_CMD52_CHK(addr);
	/*
	 * Mask addr to remove driver defined bit and
	 * make sure addr is in valid range
	 */
	if (f0)
		addr &= 0xFFF;
	else
		addr &= 0x1FFFF;

	//if (claim_needed)
		SdioClaimHost(handle);

	if (f0) {
		offset = addr;
		for (i = 0; i < len; i++, offset++) {
			value=((u8 *)buf)[i];
			error = SdioWriteBytesToFunc0(handle,&value,offset,1,0);
			if (error)
				break;
		}
	} else {
		if (cmd52) {
			offset = addr;
			for (i = 0; i < len; i++) {
				value=((u8 *)buf)[i];
				error = SdioWriteBytes(handle, &value, offset, 1,0);
				if (error)
					break;
				offset++;
				//RTW_INFO("write value:%d,buf[%d]:%d\n",value,i,((u8 *)buf)[i]);
			}
		} else {
			if(fixed==0)
			{
				error = SdioWriteBytes(handle,buf,addr,len,0);
			}
			else{
				error = SdioWriteBytesToFixedAddr(handle,buf,addr,len,0);
			}
		}
	}


	//if (claim_needed)
		SdioReleaseHost(handle);
	if(error!=0)
	{
		RTW_INFO("SdioWriteBytes error:%d\n",error);
	}

	return harmony_io_err_to_drv_err(error);
}




